﻿using KrasDD.Models;
using KrasDD.Utils;
using System.Text;

namespace KrasDD.Dtos
{


    public class QueryWrapper
    {
        public required string type { get; set; }

        public int pageIndex { get; set; } = 0;
        public int pageSize { get; set; } = 20;

        public List<ConditionDto>? conditionDtoList { get; set; }
        /// <summary>
        ///  排序字段
        /// </summary>
        public string orderBy { get; set; } = $"{nameof(AppBaseEntity.CREATED_ON)} asc";

        /// <summary>
        /// build测试 
        /// </summary>
        private void BuildTest()
        {
            var DD = JSON.Deserialize<QueryWrapper>(File.ReadAllText("E:\\Desktop\\新建文件夹 (7)\\KrasDD\\condition.json"));
            var dict = new Dictionary<string, object>();
            var lll = DD.build(dict);
        }

        public string build(Dictionary<string, object> parameters)
        {
            if (parameters == null)
                throw new ArgumentNullException(nameof(parameters));
            var tableName = DBHelper.GetTableName(type, out var dbTableInfo);
            StringBuilder sql = new StringBuilder();
            int paramIndex = parameters.Count;


            // 基础查询
            sql.Append($"SELECT * FROM  {tableName} ");

            // 构建 WHERE 条件
            if (conditionDtoList != null && conditionDtoList.Count > 0)
            {
                string whereClause = BuildConditions(conditionDtoList, ref paramIndex, parameters);
                if (!string.IsNullOrEmpty(whereClause))
                {
                    sql.Append(" WHERE ");
                    sql.Append(whereClause);
                }
            }

            // 添加分页
            if (pageSize > 0)
            {
                var parts = orderBy.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                sql.Append(parts.Length == 1 ?
                    $" ORDER BY {parts[0]}" :
                    $" ORDER BY [{parts[0]}] {parts[1]}");
                int offset = pageIndex * pageSize;
                sql.Append($" OFFSET @p{paramIndex} ROWS FETCH NEXT @p{paramIndex + 1} ROWS ONLY");
                parameters.Add($"p{paramIndex}", offset);
                parameters.Add($"p{paramIndex + 1}", pageSize);
            }

            return sql.ToString();
        }

        private string BuildConditions(List<ConditionDto> conditions, ref int paramIndex, Dictionary<string, object> parameters)
        {
            if (conditions == null || conditions.Count == 0)
                return string.Empty;

            // 按排序序号排序
            var sortedConditions = conditions.OrderBy(c => c.sortOrder).ToList();
            StringBuilder sb = new StringBuilder();
            Stack<GroupInfo> groupStack = new Stack<GroupInfo>();
            LogicalOperator? currentOperator = null;
            int i = 0;
            foreach (var condition in sortedConditions)
            {
                if (condition.isCondition)
                {
                    if (i == 0)
                    {
                        sb.Append($"( {BuildLeafCondition(condition, ref paramIndex, parameters)})");
                    }
                    else
                    {
                        sb.Append($" {condition.logicalOperator.ToString()} ({BuildLeafCondition(condition, ref paramIndex, parameters)})");
                    }
                }
                else
                {
                    if (i == 0)
                    {
                        sb.Append($" ({BuildConditions(condition.children, ref paramIndex, parameters)})");
                    }
                    else
                    {
                        sb.Append($" {condition.logicalOperator.ToString()} ({BuildConditions(condition.children, ref paramIndex, parameters)})");
                    }

                }
                i++;
            }

            // 关闭所有打开的括号
            while (groupStack.Count > 0)
            {
                sb.Append(")");
                groupStack.Pop();
            }

            return sb.ToString();
        }

        private string BuildLeafCondition(ConditionDto condition, ref int paramIndex, Dictionary<string, object> parameters)
        {
            if (string.IsNullOrWhiteSpace(condition.attrName))
            {
                return "1=1";
            }

            string paramName = $"p{paramIndex}";
            paramIndex++;

            switch (condition.oper)
            {
                case OperEnumType.Equal:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] = @{paramName}";

                case OperEnumType.NotEqual:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] <> @{paramName}";

                case OperEnumType.GreaterThan:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] > @{paramName}";

                case OperEnumType.GreaterThanOrEqual:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] >= @{paramName}";

                case OperEnumType.LessThan:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] < @{paramName}";

                case OperEnumType.LessThanOrEqual:
                    parameters.Add(paramName, condition.value);
                    return $"[{condition.attrName}] <= @{paramName}";

                case OperEnumType.Like:
                    parameters.Add(paramName, $"%{condition.value}%");
                    return $"[{condition.attrName}] LIKE @{paramName}";

                case OperEnumType.NotLike:
                    parameters.Add(paramName, $"%{condition.value}%");
                    return $"[{condition.attrName}] NOT LIKE @{paramName}";
                case OperEnumType.IsNull:
                    return $"[{condition.attrName}] IS NULL";
                case OperEnumType.IsNotNull:
                    return $"[{condition.attrName}] IS NOT NULL";
                case OperEnumType.In:
                    var inValues = condition.value.Split(',')
                        .Select(v => v.Trim())
                        .Where(v => !string.IsNullOrEmpty(v))
                        .ToArray();
                    if (inValues.Length == 0) return "1=1";

                    var inParams = new List<string>();
                    foreach (var val in inValues)
                    {
                        string inParamName = $"p{paramIndex}";
                        inParams.Add($"@{inParamName}");
                        parameters.Add(inParamName, val);
                        paramIndex++;
                    }
                    return $"[{condition.attrName}] IN ({string.Join(",", inParams)})";

                case OperEnumType.NotIn:
                    var notInValues = condition.value.Split(',')
                        .Select(v => v.Trim())
                        .Where(v => !string.IsNullOrEmpty(v))
                        .ToArray();

                    if (notInValues.Length == 0) return "1=1";

                    var notInParams = new List<string>();
                    foreach (var val in notInValues)
                    {
                        string notInParamName = $"p{paramIndex}";
                        notInParams.Add($"@{notInParamName}");
                        parameters.Add(notInParamName, val);
                        paramIndex++;
                    }
                    return $"[{condition.attrName}] NOT IN ({string.Join(",", notInParams)})";

                default:
                    return "1=1";
            }
        }

        private class GroupInfo
        {
            public LogicalOperator Operator { get; }
            public GroupInfo(LogicalOperator op) => Operator = op;
        }

    }


    public class ConditionDto
    {
        public string attrName { get; set; }          // 条件属性名（可能为空）
        public string conditionType { get; set; } = "advanced";   // 条件类型  固定advanced
        public OperEnumType oper { get; set; } = OperEnumType.Like;              // 操作符（可能为空）
        public LogicalOperator logicalOperator { get; set; } = LogicalOperator.And;   // 逻辑运算符
        public int sortOrder { get; set; } = 0;          // 排序序号
        public bool isCondition { get; set; } = true;       // 是否是条件项
        public string? value { get; set; }            // 条件值1（可能为空）
        public List<ConditionDto>? children { get; set; } // 嵌套条件
    }

    public enum LogicalOperator
    {
        /// <summary>
        /// 与
        /// </summary>
        And,

        /// <summary>
        /// 或
        /// </summary>
        Or
    }

    public enum OperEnumType
    {
        /// <summary>
        /// 等于
        /// </summary>
        Equal,

        /// <summary>
        /// 不等于
        /// </summary>
        NotEqual,

        /// <summary>
        /// 大于
        /// </summary>
        GreaterThan,

        /// <summary>
        /// 大于等于
        /// </summary>
        GreaterThanOrEqual,

        /// <summary>
        /// 小于
        /// </summary>
        LessThan,
        /// <summary>
        /// 小于等于
        /// </summary>
        LessThanOrEqual,
        /// <summary>
        /// 包含
        /// </summary>
        In,
        /// <summary>
        /// 不包含
        /// </summary>
        NotIn,

        /// <summary>
        /// 包含
        /// </summary>
        Like,
        /// <summary>
        /// 不包含
        /// </summary>
        NotLike,
        /// <summary>
        /// 为空
        /// </summary>
        IsNull,
        /// <summary>
        /// 不为空
        /// </summary>
        IsNotNull,


    }
}
